﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using BattleCore;
using BattleCore.Events;
using PsyModules;
using System.Timers;

namespace Battle
{
    // Add the attribute and the base class
    [Behavior("Main", "true", "0.01", "PsyOps", "Main module for public.")]
    public class Main: BotEventListener
    {
        // ------------------------------\\
        //  VARIABLES AND NEEDED METHODS  |
        // ------------------------------//
        // Stores botinfo
        string BotName, Arena = "";
        ushort BotID;
        bool BotOn = false;

        // Custom chat module
        ShortChat msg = new ShortChat();        
        // Main game timer
        Timer MainGameTimer = new Timer();
        // Controls battle boxes
        BattleControl m_Battle = new BattleControl();
        // Player status - Pub/ Battle/ InSpec/ Parking
        StatusControl m_Status = new StatusControl();
        // Public control
        PubControl m_Public = new PubControl();
        // Tracks ship changes
        ShipControl m_ShipList = new ShipControl();
        // Region/collision check
        RegionControl m_Regions = new RegionControl();
        // Any timer related functions
        TimerFunctions m_Timer = new TimerFunctions();
        // delay between allowed warps - prevents double warps
        double warpdelay = 3;

        //----------------------------------\\
        //       REGISTERED COMMANDS         |
        //----------------------------------//
        public Main()
        {
            RegisterCommand("!pause", doPause);
            RegisterCommand("!debug", doDebug);
            RegisterCommand("!test1", doTest);
            RegisterCommand("!test2", doTest2);
            RegisterCommand("!bonus", doBonus);
        }

        // ----------------------------\\
        //   Game Timer                 |
        // ----------------------------//
        // any timed events go inside m_Timer
        public void BattleTimer(object source, ElapsedEventArgs e)
        {
            Queue<EventArgs> commands = new Queue<EventArgs>();
            SendEvents(m_Timer.UpdateTimer());
            m_Battle.TimerBattleControl(commands);
            SendEvents(commands);
        }

        // ----------------------------\\
        //       EVENT MONITOR          |
        // ----------------------------//
        // Handles all chat events
        public void MonitorChat(object sender, ChatEvent c)
        {
            // when core starts up it sends this message with bot info attached
            if (c.ChatType == ChatTypes.Private && c.Message.StartsWith("@BotInfo@"))
                // Start Bot timer and initialize
                StartBot(c);
            else if (c.ChatType == ChatTypes.Arena && (c.Message.Equals("Damage logging ON") || c.Message.Equals("Damage logging OFF")))
            {
                // Checking for incoming *watchdamage toggle messages
                // If its off we resend command
                string DamageOn = c.Message.Split(' ')[2].ToLower();
                if (m_Timer.WatchDamageList.Count > 0 && DamageOn == "on")
                    m_Timer.NextOnWDList = m_Timer.WatchDamageList.Dequeue();
                else if (DamageOn != "on")
                    Game(msg.pm(m_Timer.NextOnWDList, "*watchdamage"));
            }
            else if ((c.ChatType == ChatTypes.Public || c.ChatType == ChatTypes.Private) && ((c.Message.StartsWith("!") || c.Message.StartsWith("."))))
            {
                StatusControl.MainPlayer m_Player = m_Status.GetPlayer(c.PlayerName);

                // Pub commands
                if (m_Player.PlayerStatus == Status.InPublic)
                    SendEvents(m_Public.PubChatCommands(c));
                else
                    SendEvents(m_Battle.BattleChatCommands(c, m_Status.GetPlayer(c.PlayerName)));
            }
        }

        public void MonitorPlayerInfoEvent(object sender, PlayerInfoEvent p)
        {
            p.PlayerList.ForEach(delegate(PlayerInfo p2)
            {
            });
        }
        public void MonitorPlayerEnterEvent(object sender, PlayerEnteredEvent p)
        {
            DelegateEvents(m_Status.GetPlayer(p.PlayerName), p);
        }
        public void MonitorPlayerPosition(object sender, PlayerPositionEvent p)
        {
            DelegateEvents(m_Status.GetPlayer(p.PlayerName), p);
        }
        public void MonitorShipChangeEvent(object sender, ShipChangeEvent s)
        {
            DelegateEvents(m_Status.GetPlayer(s.PlayerName), s);
        }
        public void MonitorFreqChange(object sender, TeamChangeEvent t)
        {
            DelegateEvents(m_Status.GetPlayer(t.PlayerName), t);
        }
        public void MonitorPrizeEvents(object sender, PrizeCollectedEvent p)
        {
            DelegateEvents(m_Status.GetPlayer(p.PlayerName), p);
        }
        public void MonitorDamage(object sender, WatchDamageEvent w)
        {
            DelegateEvents(m_Status.GetPlayer(w.PlayerName), w);
        }
        public void MonitorDeathEvents(object sender, PlayerDeathEvent p)
        {
            DelegateEvents(m_Status.GetPlayer(p.KillerName), p);
        }
        public void MonitorFlagClaimEvents(object sender, FlagClaimEvent f)
        {
            DelegateEvents(m_Status.GetPlayer(f.PlayerName), f);
        }
        public void MonitorFlagDroppedEvents(object sender, FlagDropEvent f)
        {
            DelegateEvents(m_Status.GetPlayer(f.PlayerName), f);
        }
        public void MonitorPlayerLeft(object sender, PlayerLeftEvent p)
        {
            DelegateEvents(m_Status.GetPlayer(p.PlayerName), p);
        }
        public void DelegateEvents(StatusControl.MainPlayer Player, EventArgs e)
        {
            Queue<EventArgs> commands = new Queue<EventArgs>();

            if (e is PlayerEnteredEvent)
            {
                PlayerEnteredEvent p = (e as PlayerEnteredEvent);
                m_Timer.WatchDamageList.Enqueue(p.PlayerName);

                if (m_Status.GetPlayer(p.PlayerName) == null)
                {
                    // Add player to status list
                    m_ShipList.PlayerEntered(p.PlayerName);
                    m_Status.PlayerEntered(p.PlayerName);
                    Player = m_Status.GetPlayer(p.PlayerName);
                }

                CustomIntroMessages(p.PlayerName);
            }

            if (BotOn)
            {
                if (e is ShipChangeEvent)
                {
                    ShipChangeEvent s = (e as ShipChangeEvent);
                    m_ShipList.ShipChange(s);
                }
                else if (e is TeamChangeEvent)
                {
                    Player.Freq = (e as TeamChangeEvent).Frequency;
                }
                else if (e is PlayerPositionEvent)
                {
                    PlayerPositionEvent p = (e as PlayerPositionEvent);

                    // If player is allowed to warp and is inside the StartBox
                    if ((Player.WarpStamp - DateTime.Now).Duration() > TimeSpan.FromSeconds(warpdelay))
                    {
                        // Get loaded region
                        RegionType in_box = m_Regions.GetRegion(p);

                        if (Player.PlayerStatus == Status.InBattle)
                            m_Battle.InStartBox(Player, commands);
                        if (Player.PlayerStatus != Status.InBattle)
                            m_Public.PositionEvent(Player, in_box, p, commands);
                    }
                }

                if (Player.PlayerStatus == Status.InPublic || Player.PlayerStatus == Status.Parking)
                {
                    m_Public.PublicEventHandler(Player, e, commands);
                }
                else if (Player.PlayerStatus == Status.InBattle)
                {
                    m_Battle.BattleEventHandler(m_Status,Player, e, commands);
                }
            }
            SendEvents(commands);
        }

        // ----------------------------\\
        //   BOT INITIALIZATION         |
        // ----------------------------//
        public void StartBot(ChatEvent c)
        {
            if (!BotOn)
            {
                // used for random numbers
                Random ran = new Random();
                // Catch and store bot info that core sends
                string[] data = c.Message.Split(':');
                BotName = data[1];
                Arena = data[2];
                // give bot an id
                BotID = (ushort)ran.Next(11111, 65000);

                // Add regions for collision check
                m_Regions.AddRegion(RegionType.StartBox, new ushort[] { 293 * 16, 838 * 16, 298 * 16, 843 * 16 });
                m_Regions.AddRegion(RegionType.ParkingEntrance, new ushort[] { 520 * 16, 510 * 16, 524 * 16, 514 * 16 });
                m_Regions.AddRegion(RegionType.ParkingExit, new ushort[] { 294 * 16, 817 * 16, 298 * 16, 822 * 16 });
                m_Regions.AddRegion(RegionType.InStore, new ushort[] { 781 * 16, 669 * 16, 787 * 16, 676 * 16 });
                m_Regions.AddRegion(RegionType.StoreExitLeft, new ushort[] { 775 * 16, 669 * 16, 780 * 16, 676 * 16 });
                m_Regions.AddRegion(RegionType.StoreExitRight, new ushort[] { 787 * 16, 669 * 16, 793 * 16, 676 * 16 });

                // Initialize pub control
                Queue<EventArgs> q = new Queue<EventArgs>();
                m_Public.LoadPubSettings(q);
                SendEvents(q);

                BoxLoad loadcfg = new BoxLoad();
                loadcfg.LoadBoxCFG(BotName, m_Battle.Boxes);
                m_Battle.BoxesDefault = new List<BattleBox>( m_Battle.Boxes.ToArray());

                // Configure and start main game timer
                MainGameTimer.Elapsed += new ElapsedEventHandler(BattleTimer);
                MainGameTimer.Interval = 10;
                MainGameTimer.Start();//and start it

                // set bot to on
                BotOn = true;
                Game(msg.arena("Battle Bot initialized."));
                Game(msg.pub("*specall"));
            }
        }

        // ----------------------------\\
        //   UTILITIES                  |
        // ----------------------------//
        // Unstacks event queue and sends it to game
        public void SendEvents(Queue<EventArgs> q)
        {
            while (q.Count > 0)
                Game(q.Dequeue());
        }

        public void SpecPlayer(string PlayerName)
        {
            SpectatePlayerEvent s = new SpectatePlayerEvent();
            s.PlayerName = PlayerName;
            Game(s);
        }

        // ----------------------------\\
        //   DEBUG                      |
        // ----------------------------//
        public void doBonus(ChatEvent c)
        {
            if (c.ModLevel >= ModLevels.Sysop)
            {
                Queue<EventArgs> commands = new Queue<EventArgs>();
                m_Public.ToggleBonus(c.PlayerName, commands);
                SendEvents(commands);
            }
            else
                Game(msg.pm(c.PlayerName, "As if. Try again " + c.PlayerName + "!"));
        }
        public void doTest(ChatEvent c)
        {
        }
        public void doTest2(ChatEvent c)
        {
        }
        public void doPause(ChatEvent c)
        {
            BotOn = !BotOn;
            Game(msg.arena("Bot status paused: [" + BotOn + "]"));
        }
        public void doDebug(ChatEvent c)
        {
            Game(msg.arena("]>---------------------<[  Status List  ]>---------------------<["));
            m_Status.MasterList.ForEach(delegate(StatusControl.MainPlayer p)
            {
                Game(msg.arena("Player:[" + p.PlayerName + "] Status:[" + p.PlayerStatus + "] Freq:[" + p.Freq + "]"));
            });
        }
        public void CustomIntroMessages(string PlayerName)
        {
            if (PlayerName == "PsyOps")
                Game(msg.pm(PlayerName,"Hi sexy! Welcome back."));
            else if (PlayerName.ToLower() == "hellmouth")
                Game(msg.pm(PlayerName, "Sup fag. Wanna cyber?"));
            else if (PlayerName.ToLower() == "mighty sven")
                Game(msg.pm(PlayerName, "Hi honey! I kept the bed warm, join me?"));
            else if (PlayerName.ToLower() == "woogy")
                Game(msg.pm(PlayerName, "You choke the chicken before any big date, don't you? Tell me you spank the monkey before any big date. Oh my God, he doesn't flog the dolphin before a big date. Are you crazy?"));
        }

        public override void Dispose()
        {
            throw new NotImplementedException();
        }
    }
}


